package src.Packets;

import java.io.*;
import src.Util.*;
import src.Players.Player;
import src.Main;

public class PlayerLogin
{

    public boolean login(Player p)
    {
        if(p == null || p.in == null || p.out == null)
        {
            return false;
        }
        int returnCode = 2;
        long serverSessionKey = 0, clientSessionKey = 0;
        serverSessionKey = ((long)(Math.random() * 99999999D) << 32) + (long)(Math.random() * 99999999D);
        fillInStream(1, p);
        int longPlayerName = p.inStream.readUnsignedByte();
        try
        {
            for(int i = 0; i < 8; i++)
            {
                p.out.write(i);
            }
            p.out.write(0);
        }
        catch(IOException ioe)
        {
            ioe.printStackTrace();
            return false;
        }
        p.outStream.writeQWord(serverSessionKey);
        directFlushOutStream(p);
        fillInStream(2, p);
        int loginType = p.inStream.readUnsignedByte();
        if(loginType != 16 && loginType != 18)
        {
            return false;
        }
        int loginPacketSize = p.inStream.readUnsignedByte();
        int loginEncryptPacketSize = loginPacketSize-(36 + 1 + 1 + 2);
        if(loginEncryptPacketSize <= 0)
        {
            return false;
        }
        fillInStream(loginPacketSize, p);
        int variable255 = p.inStream.readUnsignedByte();
        int clientVersion = p.inStream.readUnsignedWord();
        if(variable255 != 255 || clientVersion != 317)
        {
            return false;
        }
        int memoryType = p.inStream.readUnsignedByte();
        for(int i = 0; i < 9; i++)
        {
            int cacheIDX = p.inStream.readDWord();
        }
        loginEncryptPacketSize--;
        int encryption = p.inStream.readUnsignedByte();
        if(loginEncryptPacketSize != encryption)
        {
            return false;
        }
        encryption = p.inStream.readUnsignedByte();
        if(encryption != 10)
        {
            return false;
        }
        clientSessionKey = p.inStream.readQWord();
        serverSessionKey = p.inStream.readQWord();
        int uid = p.inStream.readDWord();
        p.username = p.inStream.readString().toLowerCase();
        Main.m.ge.loadGame(p);
        if(p.username == null)
        {
            p.username = "";
            return false;
        }
        for(int i = 0; i < p.username.length(); i++)
        {
            Character c = new Character(p.username.charAt(i));
            if(!Character.isLetterOrDigit(c) && !Character.isSpaceChar(c))
            {
                p.username = "";
                return false;
            }
        }
        if(playerOnline(p.username))
        {
            returnCode = 5;
        }
        if(bannedPlayer(p.username))
        {
            returnCode = 4;
        }
        String password = p.inStream.readString();
        if(password == null)
        {
            return false;
        }
        for(int i = 0; i < password.length(); i++)
        {
            Character c = new Character(password.charAt(i));
            if(!Character.isLetterOrDigit(c) && !Character.isSpaceChar(c))
            {
                return false;
            }
        }
        if(p.password != null && p.password != "" && !p.password.equalsIgnoreCase(password))
        {
            returnCode = 3;
        }
        else
        {
            p.password = password;
        }
        int sessionKey[] = new int[4];
        sessionKey[0] = (int)(clientSessionKey >> 32);
        sessionKey[1] = (int)clientSessionKey;
        sessionKey[2] = (int)(serverSessionKey >> 32);
        sessionKey[3] = (int)serverSessionKey;
        p.inStreamDecryption = new Cryption(sessionKey);
        for(int i = 0; i < 4; i++)
        {
            sessionKey[i] += 50;
        }
        Cryption outStreamDecryption = new Cryption(sessionKey);
        p.outStream.packetEncryption = outStreamDecryption;
        if(p.username.equals("palidino76"))
        {
            p.rights = 2;
        }
        try
        {
            p.out.write(returnCode);
            p.out.write(p.rights);
            p.out.write(0);
        }
        catch(IOException ioe)
        {
            ioe.printStackTrace();
            return false;
        }
        if(returnCode == 2)
        {
            return true;
        }
        return false;
    }

    private boolean playerOnline(String name)
    {
        for(Player p : Main.m.ge.players)
        {
            if(p != null)
            {
                if(p.username.equalsIgnoreCase(name))
                {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean bannedPlayer(String username)
    {
        try
        {
            BufferedReader in = new BufferedReader(new FileReader("./src/Data/DAT/BANNEDUSERS.DAT"));
            String bannedNames = null;
            while ((bannedNames = in.readLine()) != null)
            {
                if(username.equalsIgnoreCase(bannedNames))
                {
                    in.close();
                    return true;
                }
            }
            in.close();
        }
        catch(IOException e)
        {
            System.out.println("Critical error while checking banned players!");
        }
        return false;
    }

    private void fillInStream(int forceRead, Player p)
    {
        if(p != null && p.inStream != null && p.in != null)
        {
            try
            {
                p.inStream.resetOffset();
                p.in.read(p.inStream.getBuffer(), 0, forceRead);
            }
            catch(IOException ioe)
            {
                ioe.printStackTrace();
            }
        }
    }

    private void directFlushOutStream(Player p)
    {
        if(p != null && p.outStream != null && p.out != null)
        {
            try
            {
                p.out.write(p.outStream.getBuffer(), 0, p.outStream.getOffset());
                p.outStream.resetOffset();
            }
            catch(IOException ioe)
            {
                ioe.printStackTrace();
            }
        }
    }
}